package com.compass.doctor.ui.patient


import android.content.Context
import android.content.Intent
import android.graphics.Rect
import android.media.AudioAttributes
import android.media.AudioManager
import android.media.MediaPlayer
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.WindowManager
import androidx.activity.viewModels
import com.compass.doctor.R
import com.compass.doctor.base.BaseVBActivity
import com.compass.doctor.databinding.ActivityVideoCallBinding
import com.compass.doctor.ui.home.viewmodel.InquiryOrderViewModel
import com.compass.doctor.ui.patient.viewmodel.VideoCallViewModel
import com.compass.framework.constant.CLINICAL_RECEPTION
import com.compass.framework.constant.NIM_APP_KEY
import com.compass.framework.dialog.CommonMessageDialog
import com.compass.framework.ext.gone
import com.compass.framework.ext.onClick
import com.compass.framework.ext.toJson
import com.compass.framework.ext.visible
import com.compass.framework.helper.CompassAppHelper
import com.compass.framework.manager.UserInfoManager
import com.compass.framework.utils.LiveDataBus
import com.compass.framework.utils.LogUtil
import com.compass.framework.utils.StatusBarSettingHelper
import com.compass.framework.utils.getStringFromResource
import com.netease.lava.api.IVideoRender
import com.netease.lava.nertc.sdk.LastmileProbeResult
import com.netease.lava.nertc.sdk.NERtc
import com.netease.lava.nertc.sdk.NERtcCallback
import com.netease.lava.nertc.sdk.NERtcCallbackEx
import com.netease.lava.nertc.sdk.NERtcConstants
import com.netease.lava.nertc.sdk.NERtcEx
import com.netease.lava.nertc.sdk.NERtcUserJoinExtraInfo
import com.netease.lava.nertc.sdk.NERtcUserLeaveExtraInfo
import com.netease.lava.nertc.sdk.stats.NERtcAudioVolumeInfo
import com.netease.lava.nertc.sdk.video.NERtcEncodeConfig
import com.netease.lava.nertc.sdk.video.NERtcRemoteVideoStreamType
import com.netease.lava.nertc.sdk.video.NERtcVideoConfig
import com.netease.lava.nertc.sdk.video.NERtcVideoStreamType
import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.Observer
import com.netease.nimlib.sdk.avsignalling.SignallingServiceObserver
import com.netease.nimlib.sdk.avsignalling.constant.InviteAckStatus
import com.netease.nimlib.sdk.avsignalling.constant.SignallingEventType
import com.netease.nimlib.sdk.avsignalling.event.CanceledInviteEvent
import com.netease.nimlib.sdk.avsignalling.event.ChannelCloseEvent
import com.netease.nimlib.sdk.avsignalling.event.ChannelCommonEvent
import com.netease.nimlib.sdk.avsignalling.event.ControlEvent
import com.netease.nimlib.sdk.avsignalling.event.InviteAckEvent
import com.netease.nimlib.sdk.avsignalling.event.InvitedEvent
import com.netease.nimlib.sdk.avsignalling.event.UserJoinEvent
import com.netease.nimlib.sdk.avsignalling.event.UserLeaveEvent
import com.netease.nimlib.sdk.avsignalling.model.ChannelBaseInfo
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.nio.ByteBuffer
import java.util.UUID


/**
 * Description： 视频通话
 * Date:2024/6/13 11:07
 */
class VideoCallActivity : BaseVBActivity<ActivityVideoCallBinding>() {

    companion object {
        fun start(context: Context, account: String, orderId: String) {
            val intent = Intent(context, VideoCallActivity::class.java)
            intent.putExtra("orderId", orderId)
            intent.putExtra("account", account)
            context.startActivity(intent)
        }
    }

    private var player: MediaPlayer = MediaPlayer()
    private var invitedRequestId: String? = null
    private lateinit var account: String
    private lateinit var mOrderId: String
    private var isAnswer:Boolean=false//是否接通
    private val videoCallViewModel: VideoCallViewModel by viewModels()
    private val inquiryOrderViewModel: InquiryOrderViewModel by viewModels()

    private var onlineObserver: Observer<ChannelCommonEvent>? = null
    private var neRtcCallback: NERtcCallback = object : NERtcCallbackEx {
        override fun onUserSubStreamVideoStart(uid: Long, maxProfile: Int) {}
        override fun onUserSubStreamVideoStop(uid: Long) {}
        override fun onUserAudioMute(uid: Long, muted: Boolean) {}
        override fun onUserVideoMute(uid: Long, muted: Boolean) {}
        override fun onUserVideoMute(
            streamType: NERtcVideoStreamType,
            uid: Long,
            muted: Boolean
        ) {
        }

        override fun onFirstAudioDataReceived(uid: Long) {}

        override fun onFirstVideoDataReceived(uid: Long) {}
        override fun onFirstVideoDataReceived(streamType: NERtcVideoStreamType, uid: Long) {}
        override fun onFirstAudioFrameDecoded(userID: Long) {}
        override fun onFirstVideoFrameDecoded(userID: Long, width: Int, height: Int) {}


        override fun onFirstVideoFrameDecoded(
            streamType: NERtcVideoStreamType,
            userID: Long,
            width: Int,
            height: Int
        ) {
        }

        override fun onUserVideoProfileUpdate(uid: Long, maxProfile: Int) {}
        override fun onAudioDeviceChanged(selected: Int) {}
        override fun onAudioDeviceStateChange(deviceType: Int, deviceState: Int) {}
        override fun onVideoDeviceStageChange(deviceState: Int) {}
        override fun onConnectionTypeChanged(newConnectionType: Int) {}
        override fun onReconnectingStart() {}
        override fun onReJoinChannel(result: Int, channelId: Long) {}
        override fun onAudioMixingStateChanged(reason: Int) {}
        override fun onAudioMixingTimestampUpdate(timestampMs: Long) {}
        override fun onAudioEffectTimestampUpdate(id: Long, timestampMs: Long) {}
        override fun onAudioEffectFinished(effectId: Int) {}
        override fun onLocalAudioVolumeIndication(volume: Int) {}
        override fun onLocalAudioVolumeIndication(volume: Int, vadFlag: Boolean) {}
        override fun onRemoteAudioVolumeIndication(
            volumeArray: Array<NERtcAudioVolumeInfo>,
            totalVolume: Int
        ) {
        }

        override fun onLiveStreamState(taskId: String, pushUrl: String, liveState: Int) {}
        override fun onConnectionStateChanged(state: Int, reason: Int) {}
        override fun onCameraFocusChanged(rect: Rect) {}
        override fun onCameraExposureChanged(rect: Rect) {}
        override fun onRecvSEIMsg(userID: Long, seiMsg: String) {}
        override fun onAudioRecording(code: Int, filePath: String) {}
        override fun onError(code: Int) {}
        override fun onWarning(code: Int) {}
        override fun onApiCallExecuted(apiName: String, result: Int, message: String) {}
        override fun onMediaRelayStatesChange(state: Int, channelName: String) {}
        override fun onMediaRelayReceiveEvent(event: Int, code: Int, channelName: String) {}
        override fun onLocalPublishFallbackToAudioOnly(
            isFallback: Boolean,
            streamType: NERtcVideoStreamType
        ) {
        }

        override fun onRemoteSubscribeFallbackToAudioOnly(
            uid: Long,
            isFallback: Boolean,
            streamType: NERtcVideoStreamType
        ) {
        }

        override fun onLastmileQuality(quality: Int) {}
        override fun onLastmileProbeResult(result: LastmileProbeResult) {}
        override fun onMediaRightChange(
            isAudioBannedByServer: Boolean,
            isVideoBannedByServer: Boolean
        ) {
        }

        override fun onRemoteVideoSizeChanged(
            userId: Long,
            videoType: NERtcVideoStreamType,
            width: Int,
            height: Int
        ) {
        }

        override fun onLocalVideoRenderSizeChanged(
            videoType: NERtcVideoStreamType,
            width: Int,
            height: Int
        ) {
        }

        override fun onVirtualBackgroundSourceEnabled(enabled: Boolean, reason: Int) {}
        override fun onUserSubStreamAudioStart(uid: Long) {}
        override fun onUserSubStreamAudioStop(uid: Long) {}
        override fun onUserSubStreamAudioMute(uid: Long, muted: Boolean) {}
        override fun onPermissionKeyWillExpire() {}
        override fun onUpdatePermissionKey(key: String, error: Int, timeout: Int) {}
        override fun onLocalVideoWatermarkState(
            videoStreamType: NERtcVideoStreamType,
            state: Int
        ) {
        }

        override fun onUserDataStart(uid: Long) {}
        override fun onUserDataStop(uid: Long) {}
        override fun onUserDataReceiveMessage(
            uid: Long,
            bufferData: ByteBuffer,
            bufferSize: Long
        ) {
        }

        override fun onUserDataStateChanged(uid: Long) {}
        override fun onUserDataBufferedAmountChanged(uid: Long, previousAmount: Long) {}
        override fun onLabFeatureCallback(key: String, param: Any) {}

        //本端用户加入房间结果回调
        override fun onJoinChannel(result: Int, channelId: Long, elapsed: Long, uid: Long) {
            if (result == NERtcConstants.ErrorCode.OK) {
                // 加入房间成功
                NERtcEx.getInstance().setupLocalVideoCanvas(mBinding.videoViewBig)
                //加入房间前提前设置好视频开启状态
                NERtcEx.getInstance()
                    .enableLocalVideo(NERtcVideoStreamType.kNERtcVideoStreamTypeMain, true)

                LogUtil.d("本端用户加入房间成功", tag = tag)
            } else {
                // 加入房间失败 ，退出页面
                LogUtil.d("本端用户加入房间失败 uid: ${uid}", tag = tag)
                //结束通话
                NERtcEx.getInstance().leaveChannel()
                //释放SDK
                NERtcEx.getInstance().release()
                finish()
            }
        }

        override fun onLeaveChannel(result: Int) {}
        override fun onUserJoined(uid: Long) {
            //设置远端画布
            NERtcEx.getInstance().setupRemoteVideoCanvas(mBinding.videoViewBig, uid)
            LogUtil.d("用户加入房间", tag = tag)
        }

        override fun onUserJoined(uid: Long, joinExtraInfo: NERtcUserJoinExtraInfo) {}
        override fun onUserLeave(uid: Long, reason: Int) {

            LogUtil.d("用户离开房间回调", tag = tag)
        }

        override fun onUserLeave(
            uid: Long,
            reason: Int,
            leaveExtraInfo: NERtcUserLeaveExtraInfo
        ) {
        }

        override fun onUserAudioStart(uid: Long) {}
        override fun onUserAudioStop(uid: Long) {}
        override fun onUserVideoStart(uid: Long, maxProfile: Int) {
            NERtcEx.getInstance().setupLocalVideoCanvas(mBinding.videoViewSmall)
            //对方开启视频，按需设置画布及订阅视频
            NERtcEx.getInstance().setupRemoteVideoCanvas(mBinding.videoViewBig, uid)
            NERtcEx.getInstance().subscribeRemoteVideoStream(
                uid,
                NERtcRemoteVideoStreamType.kNERtcRemoteVideoStreamTypeHigh,
                true
            )
        }

        override fun onUserVideoStop(uid: Long) {
            //释放之前绑定的画布
            NERtcEx.getInstance().setupRemoteVideoCanvas(null, uid)
        }

        override fun onDisconnect(reason: Int) {
            // 与服务器断连 ，退出页面
            finish()
        }

        override fun onClientRoleChange(oldRole: Int, newRole: Int) {} //*******其他一些回调******
    }


    override fun initView(savedInstanceState: Bundle?) {
        StatusBarSettingHelper.setStatusBarTranslucent(this)
        StatusBarSettingHelper.statusBarLightMode(this@VideoCallActivity, true)
        account = intent.getStringExtra("account")!!
        mOrderId = intent.getStringExtra("orderId")!!
        //小画布置于大画布上面
        mBinding.videoViewSmall.setZOrderMediaOverlay(true)
        val displayMetrics: DisplayMetrics = getDisplayMetrics()
        val screenW = displayMetrics.widthPixels
        val screenH = displayMetrics.heightPixels
        mBinding.myCircle.setWidthAndHeight(screenW,screenH)
        mBinding.myCircle.setDoctorImId("1815788826166136174")
    }
    private fun getDisplayMetrics(): DisplayMetrics {
        val displayMetrics = DisplayMetrics()
        val windowManager =
            application.getSystemService(WINDOW_SERVICE) as WindowManager
        windowManager.defaultDisplay.getRealMetrics(displayMetrics)
        return displayMetrics
    }

    private fun initOnLine() {
        onlineObserver = Observer<ChannelCommonEvent> { event: ChannelCommonEvent? ->

            when (event?.eventType) {
                SignallingEventType.CLOSE -> {
                    var channelCloseEvent = event as ChannelCloseEvent
                    LogUtil.d(
                        "频道关闭事件 channelCloseEvent==${channelCloseEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.UN_KNOW -> {
                    LogUtil.d("未知事件", tag = tag)
                }

                SignallingEventType.JOIN -> {
                    var userJoinEvent = event as UserJoinEvent
                    innerStop()
                    isAnswer=true
                    mBinding.ivCancel.gone()
                    mBinding.tvCancelTip.gone()
                    mBinding.llOnTheCallOperation.visible()

                    LogUtil.d(
                        "有人加入频道事件 userJoinEvent==${userJoinEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.INVITE -> {
                    var inviteEvent = event as InvitedEvent

                    //收到邀请
                    LogUtil.d("被邀请事件  inviteEvent==${inviteEvent.toJson()}", tag = tag)
                }

                SignallingEventType.CANCEL_INVITE -> {
                    var canceledInviteEvent = event as CanceledInviteEvent

                    LogUtil.d(
                        "取消邀请事件 canceledInviteEvent==${canceledInviteEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.REJECT, SignallingEventType.ACCEPT -> {
                    var inviteAckEvent = event as InviteAckEvent

                    if (inviteAckEvent.ackStatus == InviteAckStatus.REJECT) {
                        channelInfo?.let {
                            videoCallViewModel.leave(it)
                        }
                    }
                    if (inviteAckEvent.ackStatus == InviteAckStatus.ACCEPT) {
                        switchCall = true
                    }

                    LogUtil.d(
                        "对方拒绝/接受 邀请事件 inviteAckEvent===${inviteAckEvent.toJson()}",
                        tag = tag
                    )
                }


                SignallingEventType.LEAVE -> {
                    var userLeaveEvent = event as UserLeaveEvent
                    channelInfo?.let {
                        videoCallViewModel.leave(it)
                    }
//                    inquiryOrderViewModel.finishInterrogation(mOrderId, null)
                    LogUtil.d(
                        "有用户离开频道事件  userLeaveEvent==${userLeaveEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.CONTROL -> {
                    var controlEvent = event as ControlEvent
                    LogUtil.d(
                        "自定义控制命令事件  controlEvent==${controlEvent.toJson()}",
                        tag = tag
                    )
                }

                else -> {
                    LogUtil.d("未知事件", tag = tag)
                }
            }

        }
        NIMClient.getService(SignallingServiceObserver::class.java)
            .observeOnlineNotification(onlineObserver, true)
    }

    override fun initData() {
        initOnLine()
        // 初始化SDK
        try {

            NERtc.getInstance()
                .init(CompassAppHelper.getApplication(), NIM_APP_KEY, neRtcCallback, null)
        } catch (e: Exception) {
            e.printStackTrace()
            showToast("SDK初始化失败")
            finish()
            return
        }

        //设置视频  通用 1 对 1 聊天场景
        NERtcEx.getInstance().setChannelProfile(NERtcConstants.RTCChannelProfile.LIVE_BROADCASTING)
        //设置音频profile为标准模式，scenario为语音场景
        NERtcEx.getInstance().setAudioProfile(
            NERtcConstants.AudioProfile.STANDARD,
            NERtcConstants.AudioScenario.SPEECH
        );
        //设置本地视频参数
        val videoConfig = NERtcVideoConfig()
        videoConfig.orientationMode=
            NERtcVideoConfig.NERtcVideoOutputOrientationMode.VIDEO_OUTPUT_ORIENTATION_MODE_FIXED_LANDSCAPE
        videoConfig.frameRate = NERtcEncodeConfig.NERtcVideoFrameRate.FRAME_RATE_FPS_24
        videoConfig.videoCropMode=1
        NERtcEx.getInstance().setLocalVideoConfig(videoConfig)
        // 禁用双流模式
        NERtcEx.getInstance().enableDualStreamMode(false)
        //设置本地画布
        NERtcEx.getInstance().setupLocalVideoCanvas(mBinding.videoViewBig)
        NERtcEx.getInstance().startVideoPreview(NERtcVideoStreamType.kNERtcVideoStreamTypeMain)
        mBinding.videoViewBig.setScalingType(IVideoRender.ScalingType.SCALE_ASPECT_FILL)
        var channelName = UUID.randomUUID().toString()
        //随机一个邀请id
        invitedRequestId = UUID.randomUUID().toString().trim().replace("-", "").lowercase()
        invitedRequestId?.let {
            videoCallViewModel.createRoom(channelName, account, it)
        }

        videoCallViewModel.joinChannelLiveData.observe(this) {
            it?.let {
                //加入房间
                LogUtil.d("${it.toJson()}", tag = tag)
                innerPlay(this)
                channelInfo = it.channelBaseInfo
                var channelName = it.channelBaseInfo.channelName
                UserInfoManager.getImUserAccount()?.let { uid ->
                    //token暂时传空  等后台做好了再传
                    //加入房间
                    NERtcEx.getInstance()
                        .startVideoPreview()
                    //加入房间时，调用 stopVideoPreview(streamType) 方法停止预览
                    NERtcEx.getInstance().joinChannel(null, channelName, uid.toLong(), null)
                }

            }
        }

        videoCallViewModel.leaveChannelLiveData.observe(this) {

            //结束通话
            NERtcEx.getInstance().leaveChannel()
            //释放SDK
            NERtcEx.getInstance().release()
            finish()
        }

        videoCallViewModel.cancelInviteLiveData.observe(this) {
            showToast("对方不在线，暂时无法接通")
            GlobalScope.launch {
                //结束通话
                NERtcEx.getInstance().leaveChannel()
                //释放SDK
                NERtcEx.getInstance().release()
                delay(2000L) //
                finish()
            }

        }

        inquiryOrderViewModel.finishLiveData.observe(this) {
            if (it) {
                LiveDataBus.get().with(CLINICAL_RECEPTION).postValue(CLINICAL_RECEPTION)
            }
            channelInfo?.let { it1 -> videoCallViewModel.leave(it1) }
        }
    }

    var tag = "VideoCall:==="
    private var isMuteAudio = false
    private var isMuteVideo = false
    private var channelInfo: ChannelBaseInfo? = null
    private var switchCall = false //是否接通通话
    override fun intListener() {


        mBinding.ivMuteAudio.onClick {
            isMuteAudio = !isMuteAudio
            mBinding.ivMuteAudio.setImageResource(
                if (isMuteAudio) com.netease.yunxin.nertc.ui.R.drawable.voice_off else com.netease.yunxin.nertc.ui.R.drawable.voice_on
            )
            NERtcEx.getInstance().muteLocalAudioStream(isMuteAudio)

        }


        mBinding.ivSwitchCamera.onClick {
            NERtcEx.getInstance().switchCamera()
        }

        mBinding.ivMuteVideo.onClick {
            isMuteVideo = !isMuteVideo
            mBinding.ivMuteVideo.setImageResource(if (isMuteVideo) com.netease.yunxin.nertc.ui.R.drawable.cam_off else com.netease.yunxin.nertc.ui.R.drawable.cam_on)
            NERtcEx.getInstance().muteLocalVideoStream(isMuteVideo)


        }

        mBinding.ivCancel.onClick {
            innerStop()
            //取消邀请
            invitedRequestId?.let {
                videoCallViewModel.cancelInvite(channelInfo, account, it)
            }

        }
        //通话结束
        mBinding.ivHangUp.onClick {
            channelInfo?.let {
                videoCallViewModel.leave(it)
            }
        }


    }

    private fun innerPlay(context: Context) {


        player.run {
            if (isPlaying) {
                stop()
            }
            reset()
            release()
        }
        player = MediaPlayer().apply {
            setAudioAttributes(
                AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC)
                    .build()
            )
            val afd =
                context.resources.openRawResourceFd(com.netease.yunxin.nertc.ui.R.raw.avchat_ring)
            if (afd == null) {
                LogUtil.e("can't open resources by ringId")
                return@apply
            }
            try {
                setDataSource(
                    afd.fileDescriptor,
                    afd.startOffset,
                    afd.length
                )
                isLooping = true
                prepare()
                start()
            } catch (e: Exception) {

            }
        }
    }

    private fun innerStop() {
        player.run {
            if (isPlaying) {
                stop()
            }
        }
    }

    override fun onBackPressed() {

        CommonMessageDialog.Builder(this)
            .setTitle("温馨提示")
            .setMessage("是否要结束当前通话?")
            .setConfirm(getStringFromResource(R.string.default_confirm))

            .setCancel(getString(R.string.default_cancel))
            .setonCancelListener {
                it?.dismiss()
            }
            .setonConfirmListener {
                innerStop()

                if (isAnswer) {
                    //接通了 直接离开并关闭
                    channelInfo?.let { info ->
                        videoCallViewModel.leave(info)
                    }
                }else{
                    //未接通 取消邀请离开并关闭
                    invitedRequestId?.let {
                        videoCallViewModel.cancelInvite(channelInfo, account, it)
                    }
                }

                it?.dismiss()
                super.onBackPressed()
            }.create().show()

    }

    override fun onDestroy() {
        super.onDestroy()
        innerStop()
        //结束通话
        NERtcEx.getInstance().leaveChannel()
        //释放SDK
        NERtcEx.getInstance().release()
    }
}
